package com.sky.aspect;

import com.sky.anno.TableInject;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 切面类
 *      切点 / 通知
 */
@Component
@Aspect
@Slf4j
public class TableInjectAspect {

    //切点
    //1.mapper下所有方法 => 不能定位具体的修改和添加方法
    //2.使用@TableInject注解才能增强
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.anno.TableInject)")
    public void pt(){}

    @Before("pt()")
    public void before(JoinPoint jp){
        //1.获取是具体那个方法增强(一定是增加或者修改)
        MethodSignature signature = (MethodSignature) jp.getSignature();
        Method method = signature.getMethod();
        log.info("==================================>"+method.getName()+"方法执行了");
        //2.通过method对象去获得对应的注解对象
        TableInject annotation = method.getAnnotation(TableInject.class);
        //3.获取这个方法的参数对象
        Object[] params = jp.getArgs();
        if(params == null || params.length == 0 || params.length > 1){
            return;
        }
        //这里的target就是目标方法的参数 => employee对象 / category对象
        Object target = params[0];
        //4.通过反射的方式去设置这个对象的对应成员变量的值
        //4.1 获取要设置的值
        Long userId = BaseContext.getCurrentId();
        LocalDateTime now = LocalDateTime.now();
        //4.2 获取设置对应属性的方法对象(set方法对象)
        try {
            Method createTimeMethod = target.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method updateTimeMethod = target.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method createUserMethod = target.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method updateUserMethod = target.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            //4.3 通过反射设置对应的参数
            switch (annotation.value()) {
                case INSERT:
                    //设置 创建人/创建时间/更新人/更新时间
                    createTimeMethod.invoke(target,now);
                    updateTimeMethod.invoke(target,now);
                    createUserMethod.invoke(target,userId);
                    updateUserMethod.invoke(target,userId);
                    break;
                case UPDATE:
                    //设置 更新人/更新时间
                    updateTimeMethod.invoke(target,now);
                    updateUserMethod.invoke(target,userId);
                    break;
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }
}
